﻿//
// Created by QU on 24-9-28.
//

#ifndef SESSION_H
#define SESSION_H

#include <queue>
#include <memory>
#include <mutex>
#include <atomic>
#include <stop_token>

#include <boost/asio.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>

#include "node/Node.h"
#include "server/server/NodeProcessor.h"
#include "server/server/Worker.h"

using tcp = boost::asio::ip::tcp;
namespace ip = boost::asio::ip;
namespace asio = boost::asio;

class Worker;
class NodeProcessor;

class Session : public std::enable_shared_from_this<Session>
{
public:
    static constexpr size_t MIN_BUFFER_SIZE = 20; // 初始缓冲区大小
    static constexpr size_t MAX_BUFFER_SIZE = 1024 * 1024; // 1MB
    static constexpr double EXPAND_THRESHOLD = 0.8; // 80%
    static constexpr double SHRINK_THRESHOLD = 0.2; // 20%
    static constexpr int SHRINK_DELAY = 10; // 延迟10次接收操作后才考虑收缩

    explicit Session(ip::tcp::socket&& socket, Worker& worker, std::stop_token stoken);
    ~Session();

    void startSession();
    bool isStarted() const;
    bool isClosed() const;
    void close();
    void sendNode(const std::shared_ptr<Node>& node);
    std::string getUuid() const;

private:
    void startAsyncRead();
    void continueRead();
    void handleRead(const boost::system::error_code& ec, std::size_t bytes_transferred);
    bool adjustBufferSize(size_t required_size = 0);
    [[nodiscard]] static std::shared_ptr<Node> nodeConstructor(const std::vector<std::byte>& buffer,
                                                               size_t buffer_size);
    static void processNode(NodeProcessor& processor, const std::shared_ptr<Session>& session,
                            const std::shared_ptr<Node>& node);

    void startAsyncWrite();
    void handleWrite(const boost::system::error_code& ec);

    void handleError(const boost::system::error_code& ec, const std::string& message = "");
    static std::ostream& printBuffer(std::ostream& os, const std::vector<std::byte>& buffer, size_t buffer_size,
                                     size_t header_size = Node::MAX_HEADER_SIZE);

    tcp::socket m_socket;
    boost::uuids::uuid m_uuid;
    std::atomic<bool> m_is_started { false };

    Worker& m_worker;
    std::stop_token m_session_stop_token;

    std::mutex m_send_mutex;
    std::queue<std::shared_ptr<Node>> m_send_queue;
    std::shared_ptr<Node> m_current_send_node;

    std::vector<std::byte> m_recv_buffer;
    size_t m_recv_buffer_curr_len = 0;
    std::shared_ptr<NodeProcessor> m_node_processor;

    std::atomic<bool> m_header_received_flag { false };
    uint16_t m_temp_payload_size = 0;

    int m_buffer_need_shrink_counter = 0;
};

#endif //SESSION_H
